using UnityEngine;
using System.Collections;



public class RobotController : MonoBehaviour {
	
	public float moveSpeed;
	public float panicSpeedModifier;
	private float rotationAmount;  // The amount of rotation banked from colisions
	public float rotationTime;  // The length of time (in seconds) it takes to rotate 90 degrees
	private float rotationThisUpdate;
	
	public float panicTimeLimit;
	private float panicTimer;
	
	public enum rTurnBehavior {RIGHT, LEFT, RANDOM};
	public rTurnBehavior robotTurns;
	
	private bool isPanic;
	
	private int cardinalDir;  // For storing robot facing as absolute cardinal directions.
							  // Assumes that the robot faces towards positive X when Y rotation is 0.
	
	private Vector3 tempEulerAngle;
    private int sparkParticleIndex = -1, smokeParticleIndex = -1;
	
	private enum rState {MOVING, TURNING, DIEING};
	private rState state;
	
	// Use this for initialization
	void Start () {
		rotationAmount = 0.0f;
		
		isPanic = false;
		
		tempEulerAngle = gameObject.transform.eulerAngles;
		
		cardinalDir = (int) tempEulerAngle.y / 90;  // Establishing closest cardinal direction
		
		gameObject.transform.eulerAngles.Set(tempEulerAngle.x, cardinalDir * 90f, tempEulerAngle.z);  // Locking to closest cardnial direction
		
		state = rState.MOVING;
		
		if(moveSpeed <= 0.0f ) {
			moveSpeed = 1.0f;
		}
		
		if(panicSpeedModifier <= 0.0f) {
			panicSpeedModifier = 2.0f;
		}
		
		if(rotationTime <= 0.0f) {
			rotationTime = 0.5f;
		}
		
		panicTimer = 0;

        for (int i = 0; i < gameObject.transform.GetChildCount(); ++i)
            if (gameObject.transform.GetChild(i).name == "RobotSpark")
                sparkParticleIndex = i;
            else if (gameObject.transform.GetChild(i).name == "RobotSmoke")
                smokeParticleIndex = i;

        OnDrawGizmos();
	}

    void OnDrawGizmos()
    {
        Color temp = new Color();
        switch (robotTurns)
        {
            case rTurnBehavior.LEFT:
                temp = Color.blue;
                break;
            case rTurnBehavior.RIGHT:
                temp = Color.red;
                break;
            case rTurnBehavior.RANDOM:
                temp = Color.green;
                break;
        }

        for (int j = 0; j < transform.GetChildCount(); ++j)
        {
            if ("FinalRobotMesh" == transform.GetChild(j).name)
            {
                Transform der = transform.GetChild(j);
                for (int i = 0; i < der.GetChildCount(); ++i)
                    if ("Mesh" == der.GetChild(i).name)
                    {
                        Renderer[] herp = der.GetChild(i).GetComponentsInChildren<Renderer>();
                        foreach (Renderer r in herp)
                            r.material.SetColor("_Color", temp);
                    }
                break;
            }
        }
    }

    // Update is called once per frame
    void Update()
    {
		
		if (isPanic) {
			panicTimer -= Time.deltaTime;
			
			if (panicTimer <= 0) {
				isPanic = false;
			}
		}
		
		if (!gameObject.GetComponentInChildren<Animation>().animation.isPlaying){
			
			gameObject.GetComponentInChildren<Animation>().animation.Play();
			gameObject.GetComponentInChildren<Animation>().animation["Take 001"].speed = 3;
			
		}
		
		
		while (cardinalDir < 0) {
				cardinalDir += 4;
			}
		cardinalDir = cardinalDir % 4;
		
		tempEulerAngle = gameObject.transform.eulerAngles;
		
		switch (state) {
			
			case rState.MOVING:
			
				//Debug.Log("Cardinal direction = " + cardinalDir.ToString());
			
				tempEulerAngle.y = cardinalDir * 90f;
			
				gameObject.transform.eulerAngles = tempEulerAngle;  // Locking the rotation to a cardinal direction			
						
				if (isPanic) {
					gameObject.transform.Translate(moveSpeed * Time.deltaTime * panicSpeedModifier, 0, 0);
				}
				else {
					gameObject.transform.Translate(moveSpeed * Time.deltaTime, 0, 0);  // Move forward
				}
			
				break;
			
			case rState.TURNING:
			
				rotationThisUpdate = 90f * Time.deltaTime / rotationTime;
			
				if (rotationAmount < 0) {
					rotationThisUpdate *= -1;
				}
			
				if (isPanic) {
					rotationThisUpdate *= panicSpeedModifier;
				}
			
				if ( Mathf.Abs(rotationThisUpdate) >= Mathf.Abs(rotationAmount) ) {
					rotationThisUpdate = rotationAmount;
					state = rState.MOVING;	
					//Debug.Log(gameObject.name + " state change: MOVING");
				}
			
				tempEulerAngle = gameObject.transform.eulerAngles;
			
				tempEulerAngle.y += rotationThisUpdate;
			
				rotationAmount -= rotationThisUpdate;
			
				// Debug.Log("Rotation amount = " + rotationAmount.ToString());
			
				gameObject.transform.eulerAngles = tempEulerAngle;
			
				NormalizeRotation();						
			
				break;
			
			case rState.DIEING:
				
				GameObject.Find("GameManager").GetComponent<GameManager>().robotKilled();
			
				Instantiate(GameObject.Find("DeadBot"), gameObject.transform.position, gameObject.transform.rotation);
			
				Destroy(gameObject);
			
				break;
			
			
			
	
		}
	}
		
	
	void NormalizeRotation () {
		
		tempEulerAngle = gameObject.transform.eulerAngles;
		
		while (tempEulerAngle.y >= 360f) {
			tempEulerAngle.y -= 360f;
		}
		while (tempEulerAngle.y < 0f) {
			tempEulerAngle.y += 360f;
		}
		
		gameObject.transform.eulerAngles = tempEulerAngle;
		
		
	}
	
	void OnTriggerEnter(Collider thisCollider) {
		
		if (thisCollider.tag != "Floor" && thisCollider.tag != "Crane" && thisCollider.tag != "Player") {
	
			Hazard thisHazard = thisCollider.gameObject.GetComponent<Hazard>();
			
			Vector3 closestPoint = thisCollider.ClosestPointOnBounds(gameObject.transform.position);
				
			closestPoint -= gameObject.transform.position;
			
			closestPoint.Normalize();
			
			//Debug.Log("Closest Point X: " + closestPoint.x.ToString());
			//Debug.Log("Closest Point Y: " + closestPoint.y.ToString());
			//Debug.Log("Closest Point Z: " + closestPoint.z.ToString());
					
			if(thisHazard == null && state == rState.MOVING) {  // If a valid collision
				
				
				if ( Mathf.Abs(closestPoint.x) >= Mathf.Abs(closestPoint.z) ) {  // If the collision is more significant along the x axis than the y.
					closestPoint.z = 0;  // Remove the z component
					if (closestPoint.x >= 0) {  // If x is positive
						closestPoint.x = 1;  // Set x component to positive 1
					}
					else {
						closestPoint.x = -1; // Else set x component to negative 1
					}
				}
				else {  // If the collision is more significant along the z axis
					closestPoint.x = 0;  // Remove the x component
					if (closestPoint.z >= 0) {  // If z is positive
						closestPoint.z = 1;  // Set the z component to positive 1
					}
					else {
						closestPoint.z = -1;  // Else set z component to negative 1
					}
				}
				
						
				if (isPanic) {
					closestPoint *= panicSpeedModifier;
				}
				gameObject.transform.Translate(-moveSpeed * Time.deltaTime * closestPoint.x, 0, -moveSpeed * Time.deltaTime * closestPoint.z);  // Move away by one frame step
				
				if (robotTurns == rTurnBehavior.RIGHT) {
					rotationAmount += 90.0f;
					cardinalDir++;
				}
				else if (robotTurns == rTurnBehavior.LEFT) {		
					rotationAmount -= 90.0f;
					cardinalDir--;
				} else if (robotTurns == rTurnBehavior.RANDOM) {
					if ((int) Random.Range(0,2) == 0) {
						rotationAmount += 90.0f;
						cardinalDir++;
					} 
					else {
						rotationAmount -= 90.0f;
						cardinalDir--;
					}
				}
						
				
				
				while (cardinalDir < 0) {
					cardinalDir += 4;
				}
				cardinalDir = cardinalDir % 4;
				
				state = rState.TURNING;
				//Debug.Log(gameObject.name + " state change: TURNING");
			}	
		}
	}
	
	void OnTriggerStay (Collider thisCollider) {
		
		if (thisCollider.tag != "Floor" && thisCollider.tag != "Crane"  && thisCollider.tag != "Player") {
			
			Hazard thisHazard = thisCollider.gameObject.GetComponent<Hazard>();
			
			Vector3 closestPoint = thisCollider.ClosestPointOnBounds(gameObject.transform.position);
				
			closestPoint -= gameObject.transform.position;
				
			closestPoint =  gameObject.transform.InverseTransformDirection(closestPoint);
			
			closestPoint.y = 0;
			
			closestPoint.Normalize();
			
			if (thisCollider.tag == "Robot") {
				closestPoint *= 0.4f;
			}
			
			//  Debug.Log(gameObject.name + " is pushing against " + thisCollider.gameObject.name + "\n" + "Direction is X: " + closestPoint.x.ToString() + "   Z: " + closestPoint.z.ToString());
					
			if(thisHazard == null) {  // If a valid collision	
									
				gameObject.transform.Translate( -3 * Time.deltaTime * closestPoint.x, 0, -3 * Time.deltaTime * closestPoint.z);
				
				//Debug.Log(gameObject.name + " is translating " + (-3 * Time.deltaTime * closestPoint.x).ToString() + " 0 " + (-3 * Time.deltaTime * closestPoint.z).ToString());
			}
		}
	}
	
	public bool checkIsPanic () {
		return isPanic;
	}
	
	public void setPanic () {
		
		if(panicTimeLimit > 0.0f) {
			isPanic = true;
			panicTimer = panicTimeLimit;
            //turn on the spark or smoke particles
            if (!gameObject.transform.GetChild(sparkParticleIndex).GetComponent<ParticleSystem>().isPlaying)
                gameObject.transform.GetChild(sparkParticleIndex).GetComponent<ParticleSystem>().Play();
            else if (!gameObject.transform.GetChild(smokeParticleIndex).GetComponent<ParticleSystem>().isPlaying)
                gameObject.transform.GetChild(smokeParticleIndex).GetComponent<ParticleSystem>().Play();
		}
	}
				

	public void Die () {
		state = rState.DIEING;
        gameObject.transform.GetChild(sparkParticleIndex).GetComponent<ParticleSystem>().Stop();
        gameObject.transform.GetChild(smokeParticleIndex).GetComponent<ParticleSystem>().Stop();
	}
}
